﻿using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using WinForms.Framework.Utility;

namespace WinForms.Framework.DataAnnotations
{
    /// <summary>
    /// 文字長の検証属性
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    public class StringLengthEXAttribute : StringLengthAttribute
    {
        /// <summary>
        /// 検証失敗時に出力するエラーメッセージ
        /// </summary>
        private const string ERROR_MESSAGE = "{0}は{1}文字以下で入力してください。";

        /// <summary>
        /// 検証失敗時に出力するエラーメッセージ（最小長と最大長が同一の場合）
        /// </summary>
        private const string ERROR_MESSAGE_FIXED = "{0}は{1}文字で入力してください。";

        /// <summary>
        /// 検証失敗時に出力するエラーメッセージ（最小長と最大長が指定されている場合）
        /// </summary>
        private const string ERROR_MESSAGE_RANGE = "{0}は{1}文字以上、{2}文字以下で入力してください。";

        /// <summary>
        /// 項目名
        /// </summary>
        private string _displayName;

        /// <summary>
        /// StringLengthEXAttribute クラスのインスタンスを生成します。
        /// </summary>
        public StringLengthEXAttribute(int maximumLength)
            : base(maximumLength)
        {
        }

        /// <summary>
        /// 現在の検証属性に対して、指定した値を検証します。
        /// </summary>
        /// <param name="value">検証対象の値。</param>
        /// <param name="validationContext">検証操作に関するコンテキスト情報。</param>
        /// <returns>System.ComponentModel.DataAnnotations.ValidationResult クラスのインスタンス。</returns>
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            if (MaximumLength == MinimumLength)
                ErrorMessage = ERROR_MESSAGE_FIXED;
            else if (MinimumLength > 0)
                ErrorMessage = ERROR_MESSAGE_RANGE;
            else
                ErrorMessage = ERROR_MESSAGE;

            var property = validationContext.ObjectType.GetProperty(validationContext.MemberName);
            _displayName = Attributer.HasAttribute(property, typeof(DisplayNameAttribute))
                ? Attributer.GetAttribute<DisplayNameAttribute>(property).DisplayName
                : validationContext.DisplayName;

            return base.IsValid(value, validationContext);
        }

        /// <summary>
        /// エラーが発生したデータ フィールドに基づいて、エラー メッセージに書式を適用します。
        /// </summary>
        /// <param name="name">書式設定されたメッセージに含める名前。</param>
        /// <returns>書式設定されたエラー メッセージのインスタンス。</returns>
        public override string FormatErrorMessage(string name)
        {
            return string.Format(ErrorMessageString, _displayName, MaximumLength);
        }
    }
}